﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.Configuration;
using System.Net;
using System.IO;
using System.Collections.Specialized;
using System.Web;

namespace PBDesk.Business.Facebook
{
    public class FBHelper
    {


        public static string DecodeSignedRequest(string signed_request)
        {
            string decodedPayload = null;
            string applicationSecret = ConfigurationManager.AppSettings["FacebookSecretKey"];
            string[] signedRequest = signed_request.Split('.');
            string expectedSignature = signedRequest[0];
            string payload = signedRequest[1];

            // Attempt to get same hash
            var Hmac = SignWithHmac(UTF8Encoding.UTF8.GetBytes(payload), UTF8Encoding.UTF8.GetBytes(applicationSecret));
            var HmacBase64 = ToUrlBase64String(Hmac);

            bool result = (HmacBase64 == expectedSignature);
            if (result)
            {
                decodedPayload = UTF8Encoding.UTF8.GetString(FromBase64ForUrlString(payload));

            }

            return decodedPayload;
        }

        private static byte[] FromBase64ForUrlString(string base64ForUrlInput)
        {
            int padChars = (base64ForUrlInput.Length % 4) == 0 ? 0 : (4 - (base64ForUrlInput.Length % 4));

            StringBuilder result = new StringBuilder(base64ForUrlInput, base64ForUrlInput.Length + padChars);
            result.Append(String.Empty.PadRight(padChars, '='));

            result.Replace('-', '+');
            result.Replace('_', '/');

            return Convert.FromBase64String(result.ToString());
        }



        private static string ToUrlBase64String(byte[] Input)
        {
            return Convert.ToBase64String(Input).Replace("=", String.Empty)
                                                .Replace('+', '-')
                                                .Replace('/', '_');
        }

        private static byte[] SignWithHmac(byte[] dataToSign, byte[] keyBody)
        {
            using (var hmacAlgorithm = new HMACSHA256(keyBody))
            {
                hmacAlgorithm.ComputeHash(dataToSign);
                return hmacAlgorithm.Hash;
            }
        }


        #region HTTP WEB REQUEST/RESPONSE Methods

        /// <summary>
        /// Creates the facebook request.
        /// </summary>
        /// <param name="url">The URL.</param>
        /// <param name="parameters">The parameters.</param>
        /// <returns></returns>
        internal static HttpWebRequest CreateFacebookRequest(string url, NameValueCollection parameters)
        {
            if (string.IsNullOrEmpty(url))
            {
                throw new ArgumentException("url");
            }

            HttpWebRequest request = null;

            StringBuilder buffer = new StringBuilder();

            if (parameters != null)
            {
                foreach (string key in parameters.AllKeys)
                {
                    if (buffer.Length == 0)
                    {
                        buffer.AppendFormat("?{0}={1}", key, parameters[key]);
                    }
                    else
                    {
                        buffer.AppendFormat("&{0}={1}", key, parameters[key]);
                    }
                }
            }

            request = (HttpWebRequest)HttpWebRequest.Create(url + buffer.ToString());

            return request;
        }

        /// <summary>
        /// Gets the facebook response.
        /// </summary>
        /// <param name="request">The request.</param>
        /// <returns></returns>
        private static string GetFacebookResponse(HttpWebRequest request)
        {
            
            if (request == null)
            {
                
                throw new ArgumentException("request");
            }

            StringBuilder buffer = new StringBuilder();
            
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            
            using (Stream stream = response.GetResponseStream())
            {
                Encoding encode = System.Text.Encoding.GetEncoding("utf-8");
                using (StreamReader reader = new StreamReader(stream, encode))
                {

                    char[] read = new char[256];   // read 256 characters at a time.
                    int count = reader.Read(read, 0, 256);
                    while (count > 0)
                    {
                        string line = new string(read, 0, count);
                        buffer.Append(line);
                        count = reader.Read(read, 0, 256);
                    }
                }
            }

            return buffer.ToString();
        }

        #endregion


        /// <summary>
        /// Gets the current user information.
        /// </summary>
        /// <returns></returns>
        public static string GetME(string accessToken)
        {
            const string FACEBOOK_ME_URL = "https://graph.facebook.com/me?access_token={0}";
            string result = null;

            CheckHttpsContext();

            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(
                string.Format(FACEBOOK_ME_URL, accessToken)
            );

            result = GetFacebookResponse(request);

            return result;
        }

        /// <summary>
        /// Checks if <see cref=" HttpContext"/> exists.
        /// </summary>
        private static void CheckHttpsContext()
        {
            if (HttpContext.Current == null)
            {
                throw new ApplicationException("HttpContext is not available");
            }
        }

    }
}
